package com.csproj.basic.service;

import com.csproj.basic.BasicService;
import com.csproj.basic.domain.FixedReadingDevice;
import com.csproj.basic.domain.Site;
import com.csproj.basic.repository.FixedReadingDeviceRepository;
import com.csproj.basic.repository.SiteRepository;
import com.csproj.basic.service.dto.FixedReadingDeviceDTO;
import com.csproj.basic.service.mapper.FixedReadingDeviceMapper;
import com.csproj.siiat.base.common.dto.BaseDTO;
import com.csproj.siiat.base.common.exception.BaseAppException;
import com.csproj.siiat.base.common.util.FileUtils;
import com.csproj.siiat.base.common.util.poi.POIUtil;
import com.csproj.siiat.security.SecurityUtils;
import com.csproj.system.service.UserInfoService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Service Implementation for managing FixedReadingDevice.
 */
@Service
@Transactional
public class FixedReadingDeviceService extends BasicService<FixedReadingDeviceDTO> {

    private final Logger log = LoggerFactory.getLogger(FixedReadingDeviceService.class);

    private final FixedReadingDeviceRepository fixedReadingDeviceRepository;

    private final FixedReadingDeviceMapper fixedReadingDeviceMapper;

    private final UserInfoService userInfoService;

    private final SiteRepository siteRepository;

    public FixedReadingDeviceService(FixedReadingDeviceRepository fixedReadingDeviceRepository, FixedReadingDeviceMapper fixedReadingDeviceMapper, UserInfoService userInfoService, SiteRepository siteRepository) {
        this.fixedReadingDeviceRepository = fixedReadingDeviceRepository;
        this.fixedReadingDeviceMapper = fixedReadingDeviceMapper;
        this.userInfoService = userInfoService;
        this.siteRepository = siteRepository;
    }

    /**
     * 保存固定设备信息并且返回前端需要发的dto，包括扩展属性createName
     *
     * @param fixedReadingDeviceDTO
     * @return fixedReadingDeviceDTO
     * TODO 主要负责从前端接收值
     * TODO 其他业务方法，比如保存试卷时同时保存章节
     * TODO DTO的扩展属性，在此方法复制
     */
    public FixedReadingDeviceDTO saveAndGetDTO(FixedReadingDeviceDTO fixedReadingDeviceDTO) {
        FixedReadingDevice device = fixedReadingDeviceMapper.toEntity(fixedReadingDeviceDTO);
        device = save(device);
        fixedReadingDeviceDTO = fixedReadingDeviceMapper.toDto(device);
        extendSiteName(fixedReadingDeviceDTO);
        return fixedReadingDeviceDTO;
    }

    /**
     * 保存PDA信息
     *
     * @param fixedReadingDevice
     * @return fixedReadingDevice
     * TODO 纯粹的保存方法，通用于所有保存业务调用
     * TODO 赋默认值，保存后，检查数据库，是否所有字段都有准确值
     */
    public FixedReadingDevice save(FixedReadingDevice fixedReadingDevice) {
        FixedReadingDevice entity = fixedReadingDeviceRepository.findFirstByDeviceNoAndDeletedFlagIsFalse(fixedReadingDevice.getDeviceNo());

        if(StringUtils.isNotBlank(fixedReadingDevice.getId())){
            if(entity!=null && !entity.getId().equals(fixedReadingDevice.getId())) {
                throw new BaseAppException(false,"duplicate_name");
            }

        }else if(entity!=null){
            throw  new BaseAppException(false,"duplicate_name");
        }
        fixedReadingDevice.setCreationTime(ZonedDateTime.now());
        fixedReadingDevice.setCreatorUserId(SecurityUtils.getCurrentUserId());
        fixedReadingDevice.setLastModificationTime(ZonedDateTime.now());
        fixedReadingDevice.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        fixedReadingDevice.setDeletedFlag(false);
        return fixedReadingDeviceRepository.save(fixedReadingDevice);
    }

    /**
     * 获取所有PDA信息
     *
     * @return the list of entities
     */
    @Transactional(readOnly = true)
    public List<FixedReadingDeviceDTO> findAll() {
        List<FixedReadingDeviceDTO> result = fixedReadingDeviceRepository.findAll().stream()
                .map(fixedReadingDeviceMapper::toDto)
                .collect(Collectors.toCollection(LinkedList::new));
        extendSiteName(result);
        return result;
    }

    /**
     * 获取所有PDA信息（分页）
     *
     * @return the list of entities
     * <p>
     * TODO 返回纯粹的数据库对象，不包含扩展属性，适用于所有调取业务方法
     */
    @Transactional(readOnly = true)
    public Page<FixedReadingDevice> findPageList(Map<String, Object> map, Pageable pageable) {
        //根据角色确认查询
        String siteId = userInfoService.getCurrentUserSiteId();
        if (map.get("siteId") == null) {
            map.put("siteId", siteId);
        }
        Page<FixedReadingDevice> result = fixedReadingDeviceRepository.findPageList(map, pageable);
        return result;
    }

    /**
     * 获取所有读写设备信息（分页）
     *
     * @return the list of entities
     * <p>
     * TODO 返回DTO，包含扩展属性
     * TODO 如果扩展属性不同，findPageListAndGetDTO1、findPageListAndGetDTO2，注明扩展的属性
     */
    @Transactional(readOnly = true)
    public BaseDTO findPageListAndGetDTO(Map<String, Object> map, Pageable pageable) {
        Page<FixedReadingDevice> result = findPageList(map, pageable);
        List<FixedReadingDevice> devices = result.getContent();
        List<FixedReadingDeviceDTO> fixedReadingDeviceDTOS = fixedReadingDeviceMapper.toDto(devices);

        extendSiteName(fixedReadingDeviceDTOS);
        return BaseDTO.createBaseDTO(result).setFieldList(fixedReadingDeviceDTOS);
    }


    /**
     * 根据id，获取读写设备信息
     *
     * @param id 主键id
     * @return creator、questionTypeName
     * <p>
     * TODO 返回DTO，包含扩展属性
     * TODO 如果扩展属性不同，findPageListAndGetDTO1、findPageListAndGetDTO2，注明扩展的属性
     */
    @Transactional(readOnly = true)
    public FixedReadingDeviceDTO findOneAndGetDTO(String id) {
        FixedReadingDevice fixedReadingDevice = findOne(id);
        FixedReadingDeviceDTO fixedReadingDeviceDTO = fixedReadingDeviceMapper.toDto(fixedReadingDevice);

        extendSiteName(fixedReadingDeviceDTO);
        return fixedReadingDeviceDTO;
    }

    /**
     * 根据id，获取读写设备信息
     *
     * @param id the id of the entity
     * @return the entity
     * <p>
     * TODO 返回纯粹的数据库对象，不包含扩展属性，适用于所有调取业务方法
     */
    @Transactional(readOnly = true)
    public FixedReadingDevice findOne(String id) {
        FixedReadingDevice fixedReadingDevice = fixedReadingDeviceRepository.findOne(id);
        if (fixedReadingDevice == null) {
            throw new BaseAppException(BaseDTO.CODE_PARAM, "id_errors");
        }
        return fixedReadingDevice;
    }

    /**
     * 修改读写设备并且返回前端需要发的dto，包括扩展属性
     *
     * @param deviceDTO
     * @return deviceDTO
     * TODO 类似SAVE
     */
    public FixedReadingDeviceDTO updateAndGetDTO(FixedReadingDeviceDTO deviceDTO) {
        FixedReadingDevice entity = fixedReadingDeviceMapper.toEntity(deviceDTO);
        entity = update(entity);
        FixedReadingDeviceDTO result = fixedReadingDeviceMapper.toDto(entity);
        extendSiteName(result);
        return result;
    }


    /**
     * 根据id，删除PDA信息
     *
     * @param id the id of the entity
     */
    public void delete(String id) {
        FixedReadingDevice pdaDb = findOne(id);
        pdaDb.setDeletedFlag(true);
        pdaDb.setDeletionTime(ZonedDateTime.now());
        pdaDb.setDeleterUserId(SecurityUtils.getCurrentUserId());
        pdaDb = fixedReadingDeviceRepository.save(pdaDb);
    }

    /**
     * 修改机构
     *
     * @param fixedReadingDevice
     * @return warehouse
     * TODO 类似SAVE
     */
    public FixedReadingDevice update(FixedReadingDevice fixedReadingDevice) {
        FixedReadingDevice entity = fixedReadingDeviceRepository.findFirstByDeviceNoAndDeletedFlagIsFalse(fixedReadingDevice.getDeviceNo());

        if(StringUtils.isNotBlank(fixedReadingDevice.getId())){
            if(entity!=null && !entity.getId().equals(fixedReadingDevice.getId())) {
                throw new BaseAppException(false,"duplicate_name");
            }

        }else if(entity!=null){
            throw  new BaseAppException(false,"duplicate_name");
        }

        FixedReadingDevice deviceDB = findOne(fixedReadingDevice.getId());
        deviceDB.setDeviceNo(fixedReadingDevice.getDeviceNo());
        deviceDB.setSiteId(fixedReadingDevice.getSiteId());
        deviceDB.setLastModificationTime(ZonedDateTime.now());
        deviceDB.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        deviceDB = fixedReadingDeviceRepository.save(deviceDB);
        return deviceDB;
    }

    /**
     * 获取状态
     *
     * @param id the id of the entity
     */
    public FixedReadingDeviceDTO status(String id, boolean enable) {
        FixedReadingDevice deviceDB = findOne(id);
        deviceDB.setEnableFlag(enable);
        deviceDB.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        deviceDB.setLastModificationTime(ZonedDateTime.now());
        deviceDB = fixedReadingDeviceRepository.save(deviceDB);

        FixedReadingDeviceDTO result = fixedReadingDeviceMapper.toDto(deviceDB);
        extendSiteName(result);
        return result;
    }

    /**
     * 设置固定式设备的使用状态：禁用，启用，默认为启用
     *
     * @param fixedReadingDeviceDTO
     * @return
     */
    public FixedReadingDeviceDTO updateDeviceStatus(FixedReadingDeviceDTO fixedReadingDeviceDTO) {
        FixedReadingDevice deviceDB = findOne(fixedReadingDeviceDTO.getId());
        deviceDB.setEnableFlag(fixedReadingDeviceDTO.getEnableFlag());
        deviceDB.setReason(fixedReadingDeviceDTO.getReason());
        deviceDB.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        deviceDB.setLastModificationTime(ZonedDateTime.now());
        deviceDB = fixedReadingDeviceRepository.save(deviceDB);

        FixedReadingDeviceDTO result = fixedReadingDeviceMapper.toDto(deviceDB);
        return result;
    }


    /**
     * 上传文件
     *
     * @param file
     */
    public String uploadFile(HttpServletRequest request, MultipartFile file) {
        String filePath = FileUtils.excelUpload(request, file, File.separator + "upload" + File.separator + "site");
        return filePath;
    }

    /**
     * 查询
     *
     * @return
     */
    public Map<String, Object> getStatistics() {
        Map<String, Object> statics = new HashMap<>();
        //获取未分配数量
        String siteId = userInfoService.getCurrentUserSiteId();
        String siteName = "";
        if (StringUtils.isNotBlank(siteId)&& siteId!="nositeID") {
            List<FixedReadingDevice> allTotal = fixedReadingDeviceRepository.findBySiteIdAndEnable(siteId, true);

            Site site = siteRepository.findById(siteId);
            if (site != null) {
                siteName = site.getSiteName();
            }
            List<FixedReadingDevice> installDevice = fixedReadingDeviceRepository.findBySiteIdAndInstall(siteId,true,true);
            statics.put("installCount",installDevice.size());
            statics.put("totalCount", allTotal.size());

        } else {
            List<FixedReadingDevice> allTotal = fixedReadingDeviceRepository.findAll();
            List<FixedReadingDevice> fixedReadingDevices = fixedReadingDeviceRepository.findByUnSiteId();
            statics.put("stock", fixedReadingDevices.size());
            statics.put("totalCount", allTotal.size());
        }
        statics.put("siteName", siteName);
        return statics;
    }

    /**
     * 上传文件
     * @param file
     */
    public BaseDTO  batchImport(MultipartFile file){
        try {
            List<String[]> readResult = POIUtil.readExcel(file);

            if(readResult.size()==0)
            {
                return  BaseDTO.createBaseDTO().setSuccess(false).setMessage("upload_faild");
            }
            List<FixedReadingDevice> devices = new ArrayList<>();
            List<Site> sites = siteRepository.findAll();
            StringBuilder errmsg = new StringBuilder();
            int i = 2;
            for (String[] u : readResult) {
                try {
                    FixedReadingDevice uname = fixedReadingDeviceRepository.findFirstByDeviceNoAndDeletedFlagIsFalse(u[0]);
                    if(uname!=null){
                        errmsg.append(i-1).append(",");
                    }else{

                        FixedReadingDevice device = new FixedReadingDevice();
                        i++;
                        device.setDeletedFlag(false);
                        device.setEnableFlag(true);
                        device.setDeviceNo(u[0]);
                        if(StringUtils.isNotBlank(u[1]))
                        {
                            Site site = sites.stream().filter(s->s.getSiteName().equals(StringUtils.trim(u[1]))).findFirst().orElse(new Site());
                            device.setSiteId(site.getId());
                        }
                        devices.add(device);
                    }

                }catch (Exception e){
                    errmsg.append(i-1).append(",");
                }
            }

            if(devices.size()>0)
                fixedReadingDeviceRepository.save(devices);
            String msg = "";
            if(errmsg.length()>0)
            {
                return  BaseDTO.createBaseDTO().setSuccess(false).setMessage("partial_upload_faild");
            }
        } catch (IOException e) {
            throw new BaseAppException(false,"upload_error");
        }
        return BaseDTO.createBaseDTO().setSuccess(true);
    }
}
